/*- * See the file LICENSE for redistribution information. * * Copyright (c) 2002-2006 * Sleepycat Software. All rights reserved. * * $Id: XAEnvironment.java,v 1.1 2006/05/06 08:59:33 ckaestne Exp $ */ package com.sleepycat.je; import java.io.File; import javax.transaction.xa.XAException; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; import com.sleepycat.je.txn.Txn; import com.sleepycat.je.txn.TxnManager; /** * Javadoc for this public class is generated * via the doc templates in the doc_src directory. */ public class XAEnvironment extends Environment implements XAResource { private static final boolean DEBUG = false; /** * Javadoc for this public method is generated via * the doc templates in the doc_src directory. */ public XAEnvironment(File envHome, EnvironmentConfig configuration) throws DatabaseException { super(envHome, configuration); } /** * Used to get the Transaction object given an XA Xid. */ public Transaction getXATransaction(Xid xid) throws DatabaseException { Txn ret = environmentImpl.getTxnManager().getTxnFromXid(xid); if (ret == null) { return null; } /* Do we guarantee object identity for Transaction objects? */ return new Transaction(this, ret); } /** * Used to set the Transaction object for an XA Xid. Public for tests. */ public void setXATransaction(Xid xid, Transaction txn) throws DatabaseException { environmentImpl.getTxnManager(). registerXATxn(xid, txn.getTxn(), false); } /* * XAResource methods. */ /** * Javadoc for this public method is generated via * the doc templates in the doc_src directory. */ public void commit(Xid xid, boolean ignore /*onePhase*/) throws XAException { if (DEBUG) { System.out.println("*** commit called " + xid + "/" + ignore); } if (xid == null) { return; } try { checkEnv(); Transaction txn = getXATransaction(xid); if (txn == null) { throw new XAException ("No transaction found for " + xid + " during commit."); } removeReferringHandle(txn); if (txn.getTxn().getOnlyAbortable()) { throw new XAException(XAException.XA_RBROLLBACK); } txn.getTxn().commit(xid); } catch (DatabaseException DE) { throwNewXAException(DE); } if (DEBUG) { System.out.println("*** commit finished"); } } /** * Javadoc for this public method is generated via * the doc templates in the doc_src directory. */ public void end(Xid xid, int flags) throws XAException { if (DEBUG) { System.out.println("*** end called " + xid + "/" + flags); } /* flags - One of TMSUCCESS, TMFAIL, or TMSUSPEND. */ boolean tmFail = (flags & XAResource.TMFAIL) != 0; boolean tmSuccess = (flags & XAResource.TMSUCCESS) != 0; boolean tmSuspend = (flags & XAResource.TMSUSPEND) != 0; if ((tmFail && tmSuccess) || ((tmFail || tmSuccess) && tmSuspend)) { throw new XAException(XAException.XAER_INVAL); } try { if (DEBUG) { System.out.println ("Transaction for " + Thread.currentThread() + " is " + environmentImpl.getTxnManager().getTxnForThread()); } Transaction txn = environmentImpl.getTxnManager().unsetTxnForThread(); if (txn == null) { txn = getXATransaction(xid); boolean isSuspended = (txn != null) && txn.getTxn().isSuspended(); if (!isSuspended) { throw new XAException(XAException.XAER_NOTA); } } if (tmFail) { txn.getTxn().setOnlyAbortable(); } if (tmSuspend) { txn.getTxn().setSuspended(true); } } catch (DatabaseException DE) { throwNewXAException(DE); } } /** * Javadoc for this public method is generated via * the doc templates in the doc_src directory. */ public void forget(Xid xid) throws XAException { if (DEBUG) { System.out.println("*** forget called"); } throw new XAException(XAException.XAER_NOTA); } /** * Javadoc for this public method is generated via * the doc templates in the doc_src directory. */ public boolean isSameRM(XAResource rm) throws XAException { if (DEBUG) { System.out.println("*** isSameRM called"); } try { checkEnv(); } catch (DatabaseException DE) { throwNewXAException(DE); } if (rm == null) { return false; } if (!(rm instanceof XAEnvironment)) { return false; } return environmentImpl == DbInternal.envGetEnvironmentImpl((XAEnvironment) rm); } /** * Javadoc for this public method is generated via * the doc templates in the doc_src directory. */ public int prepare(Xid xid) throws XAException { if (DEBUG) { System.out.println("*** prepare called"); } try { checkEnv(); Transaction txn = getXATransaction(xid); if (txn == null) { throw new XAException ("No transaction found for " + xid + " during prepare."); } txn.getTxn().prepare(xid); if (DEBUG) { System.out.println("*** prepare returning XA_OK"); } return XAResource.XA_OK; } catch (DatabaseException DE) { throwNewXAException(DE); } return XAResource.XA_OK; // for compiler } /** * Javadoc for this public method is generated via * the doc templates in the doc_src directory. */ public Xid[] recover(int flags) throws XAException { if (DEBUG) { System.out.println("*** recover called"); } /* flags - One of TMSTARTRSCAN, TMENDRSCAN, TMNOFLAGS. */ boolean tmStartRScan = (flags & XAResource.TMSTARTRSCAN) != 0; boolean tmEndRScan = (flags & XAResource.TMENDRSCAN) != 0; if ((tmStartRScan && tmEndRScan) || (!tmStartRScan && !tmEndRScan && flags != TMNOFLAGS)) { throw new XAException(XAException.XAER_INVAL); } /* * We don't have to actually do anything with STARTRSCAN or ENDRSCAN * since we return the whole set of Xid's to be recovered on each call. */ try { checkHandleIsValid(); checkEnv(); if (DEBUG) { System.out.println("*** recover returning1"); } return environmentImpl.getTxnManager().XARecover(); } catch (DatabaseException DE) { throwNewXAException(DE); } return null; // for compiler } /** * Javadoc for this public method is generated via * the doc templates in the doc_src directory. */ public void rollback(Xid xid) throws XAException { if (DEBUG) { System.out.println("*** rollback called"); } try { checkEnv(); Transaction txn = getXATransaction(xid); if (txn == null) { throw new XAException ("No transaction found for " + xid + " during abort."); } removeReferringHandle(txn); txn.getTxn().abort(xid); } catch (DatabaseException DE) { throwNewXAException(DE); } if (DEBUG) { System.out.println("*** rollback returning"); } } /** * Javadoc for this public method is generated via * the doc templates in the doc_src directory. */ public int getTransactionTimeout() throws XAException { try { return (int) ((getConfig().getTxnTimeout() + 999999L) / 1000000L); } catch (Exception DE) { throwNewXAException(DE); } return 0; // for compiler } /** * Javadoc for this public method is generated via * the doc templates in the doc_src directory. */ public boolean setTransactionTimeout(int timeout) throws XAException { return false; } /** * Javadoc for this public method is generated via * the doc templates in the doc_src directory. */ public void start(Xid xid, int flags) throws XAException { if (DEBUG) { System.out.println("*** start called " + xid + "/" + flags); } boolean tmJoin = (flags & XAResource.TMJOIN) != 0; boolean tmResume = (flags & XAResource.TMRESUME) != 0; /* Check flags - only one of TMNOFLAGS, TMJOIN, or TMRESUME. */ if (xid == null || (tmJoin && tmResume) || (!tmJoin && !tmResume && flags != XAResource.TMNOFLAGS)) { throw new XAException(XAException.XAER_INVAL); } try { Transaction txn = getXATransaction(xid); TxnManager txnMgr = environmentImpl.getTxnManager(); if (flags == XAResource.TMNOFLAGS) { /* * If neither RESUME nor JOIN was set, make sure xid doesn't * exist in allXATxns. Throw XAER_DUPID if it does. */ if (txn == null) { if (DEBUG) { System.out.println ("Transaction for XID " + xid + " being created"); } txn = beginTransaction(null, null); setXATransaction(xid, txn); } else { throw new XAException(XAException.XAER_DUPID); } } else if (tmJoin) { if (txn == null) { throw new XAException(XAException.XAER_NOTA); } if (txnMgr.getTxnForThread() != null) { throw new XAException(XAException.XAER_PROTO); } } else if (tmResume) { if (txn == null) { throw new XAException(XAException.XAER_NOTA); } if (!txn.getTxn().isSuspended()) { throw new XAException(XAException.XAER_PROTO); } txn.getTxn().setSuspended(false); } if (DEBUG) { System.out.println ("Setting Transaction for " + Thread.currentThread()); } txnMgr.setTxnForThread(txn); } catch (DatabaseException DE) { if (DEBUG) { System.out.println("*** start exception"); } throwNewXAException(DE); } if (DEBUG) { System.out.println("*** start finished"); } } private void throwNewXAException(Exception E) throws XAException { XAException ret = new XAException(E.toString()); ret.initCause(E); throw ret; } }